package com.gin.kotlin.no_gay_alliance.base

import android.animation.LayoutTransition
import android.content.Intent
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.os.Parcelable
import android.util.Log
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MotionEvent
import android.view.ViewGroup
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.viewbinding.ViewBinding
import androidx.viewpager2.widget.ViewPager2
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.gin.kotlin.no_gay_alliance.R
import com.gin.kotlin.no_gay_alliance.enums.NgaTheme
import com.gin.kotlin.no_gay_alliance.store.GlobalProperty
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import java.lang.reflect.ParameterizedType
import kotlin.math.abs

/**
 *  ViewBinding模式下的基础活动
 * @param T: ViewBinding
 */
abstract class AbstractBindingActivity<T : ViewBinding> : AppCompatActivity(), ViewBindProvider<T>, Handler.Callback, HandlerHolder {
    protected val TAG: String = this::class.java.simpleName

    /**
     * Binding对象
     */
    var b: T? = null

    /**
     * 顶部标题栏组件
     */
    var toolbar: Toolbar? = null

    /**
     * handler
     */
    override var handler: MyHandler? = null

    protected var startX = 0
    protected var startY = 0

    /**
     * 上下划时阻止翻页
     * @param ev MotionEvent
     * @return Boolean
     */
    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        val viewPager2 = b?.root?.findViewById<ViewPager2>(R.id.view_pager2) ?: return super.dispatchTouchEvent(ev)
        when (ev?.action) {
            // 起点位置
            MotionEvent.ACTION_DOWN -> {
                startX = ev.x.toInt()
                startY = ev.y.toInt()
            }
            //划动
            MotionEvent.ACTION_MOVE -> {
                val dX = abs(ev.x.toInt() - startX)
                val dY = abs(ev.y.toInt() - startY)
                if (dY > dX && viewPager2.isUserInputEnabled) {
//                    Log.d(TAG, "dispatchTouchEvent: 阻止ViewPager2翻页")
                    viewPager2.isUserInputEnabled = false
                }
            }

            MotionEvent.ACTION_UP -> {
                startX = 0
                startY = 0
                viewPager2.isUserInputEnabled = true
//                Log.d(TAG, "dispatchTouchEvent: 允许ViewPager2翻页")
            }
        }
        return super.dispatchTouchEvent(ev)
    }

    /**
     * 根据AttrId获取 colorID
     */
    @ColorInt
    fun getAttrColor(@AttrRes attrId: Int): Int {
        val typedValue = TypedValue()
        this.theme.resolveAttribute(attrId, typedValue, true)
        return typedValue.data
    }

    /**
     * 注册一个活动启动器，用于在需要活动返回处理结果时
     * @param callback 回调，建议使用this
     * @return ActivityResultLauncher<Intent>
     */
    fun registerLauncher(callback: ActivityResultCallback<ActivityResult>) =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult(), callback)

    /**
     * 获取当前activity中的指定位置的子fragment
     *
     * @param position 位置
     * @return Fragment
     */
    fun findCurrentFragment(position: Int) = supportFragmentManager.findFragmentByTag("f$position")


    /**
     * 配置Toolbar, onCreated方法中会调用，如果此时未提供则需要后续手动调用
     * @param toolbar Toolbar?
     * @return Toolbar?
     */
    fun configToolbar(toolbar: Toolbar?) = toolbar?.also {
        this.toolbar = toolbar
        setSupportActionBar(toolbar)
        toolbar.setNavigationOnClickListener { finish() }
    }


    /**
     * 设置Toolbar的标题
     * @param title String
     */
    fun setToolbarTitle(title: String) {
        if (this.toolbar != null) {
            this.toolbar!!.setTitle(title)
        } else {
            Log.w(TAG, "setToolbarTitle: Toolbar未装载")
        }
    }


    /**
     * 生命周期 onCreate
     */
    final override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //  设置主题
        configTheme()

        // 渲染View
        this.b = instanceViewBinding(LayoutInflater.from(this))?.also { setContentView(it.root) }
        // 渐变过渡
        (b?.root as? ViewGroup)?.layoutTransition = LayoutTransition().also { it.enableTransitionType(LayoutTransition.CHANGING) }

        // 初始化handler
        this.handler = MyHandler(this, this)

        val tb = b?.root?.findViewById<Toolbar>(R.id.toolbar)
//        val tb = findToolBar()
        if (tb == null) {
            Log.w(TAG, "onCreate: 未装载Toolbar, 请后续手动装载Toolbar，并执行 configToolbar 方法")
        } else {
            this.toolbar = tb
            this.configToolbar(tb)
        }
        // 解析意图
        intent?.also { handleIntent(it) }
        // 后续操作
        onCreate()
    }

    /**
     * 配置主题配色
     */
    private fun configTheme() {
        val globalProperty = GlobalProperty.getInstance()
        // 系统当前是否处于深色模式
        val systemUiModeNight = resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES

        if (systemUiModeNight && globalProperty.themeFollow) {
            setTheme(NgaTheme.BLACK.styleId)
        } else {
            setTheme(globalProperty.theme.styleId)
        }
    }

    final override fun onCreateOptionsMenu(menu: Menu): Boolean {
        showMenuIcon(menu)
        // 装载菜单
        onCreateOptionsMenu(menu, menuInflater)
        return super.onCreateOptionsMenu(menu)
    }

    /**
     * (使用反射默认实现)
     * 实例化 ViewBinding 对象, 使用对应模板的Binding类的inflate方法进行构造
     * @param inflater 渲染器
     * @param container 容器(Fragment用)
     * @return T
     */
    override fun instanceViewBinding(inflater: LayoutInflater, container: ViewGroup?): T? {
        val parameterizedType =
            findParameterizedType(this.javaClass) ?: throw RuntimeException("ViewBinding创建失败: ${this.javaClass.simpleName}, 泛型未找到")
        for (type in parameterizedType.actualTypeArguments) {
            if (type is Class<*>) {
                try {
                    val method = type.getMethod("inflate", LayoutInflater::class.java)
                    @Suppress("UNCHECKED_CAST")
                    return method.invoke(type, inflater) as T
                } catch (e: NoSuchMethodException) {
                    Log.d(TAG, "instanceViewBinding: 方法未找到")
                }
            }
        }
        Log.w(TAG, "instanceViewBinding: 实例化失败, 请实现本方法")
        return null
    }

    override fun onDestroy() {
        super.onDestroy()
        this.handler?.onDestroy()
        this.handler = null
    }

    /**
     * handler处理消息的回调
     * @param msg Message
     * @return 是否消耗该消息
     */
    override fun handleMessage(msg: Message) = true

    override fun onResume() {
        super.onResume()

        // 设置初始标题
        intent?.getStringExtra(INTENT_KEY_INIT_TITLE)?.also { setToolbarTitle(it) }
    }


    /**
     * 装载右上角菜单, 使用 [MenuInflater.inflate] 方法
     * @param menu Menu
     * @param menuInflater MenuInflater
     */
    open fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {}

    /**
     * onCreate方法的后续操作，如 [AbstractBindingActivity.registerLauncher]， 或 [AbstractBindingActivity.attachTabLayout]
     */
    abstract fun onCreate()

    /**
     * 解析意图
     * @param intent Intent?
     */
    abstract fun handleIntent(intent: Intent)

    companion object {
        val mapper: ObjectMapper = ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL).registerModule(JavaTimeModule())

        /**
         * 意图中的字段，用于设置初始标题
         */
        const val INTENT_KEY_INIT_TITLE = "INIT_TITLE"

        /**
         * 从意图中直接，或意图中的url中解析参数
         * @param intent Intent
         * @param kClass Class<T>
         * @param fromUrl Function1<[@kotlin.ParameterName] String?, T>
         * @return T
         */
        fun <T : Any> parseArgument(intent: Intent, argumentKey: String, kClass: Class<T>, fromUrl: ((url: String?) -> T?)? = null): T {
            val a0 = if (kClass == String::class.java) intent.getStringExtra(argumentKey) as? T else null
            val a1 = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) intent.getParcelableExtra(argumentKey, kClass) else null
            val a2: T? = intent.getParcelableExtra(argumentKey)
            val a3 = fromUrl?.invoke(intent.dataString)
            val argument = a0 ?: a1 ?: a2 ?: a3 ?: throw RuntimeException("必须提供参数")
            Log.i(this::class.java.simpleName, "获得参数: ${mapper.writeValueAsString(argument)}")
            return argument
        }


        fun <T : Parcelable> parseArgumentList(
            intent: Intent, key: String, cls: Class<T>
        ) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            intent.getParcelableArrayListExtra(key, cls)
        } else {
            intent.getParcelableArrayListExtra(key)
        } ?: throw RuntimeException("必须提供参数")

        /**
         * 递归查找泛型类型
         *
         * @param clazz 类对象
         * @return 泛型类型
         */
        fun findParameterizedType(clazz: Class<*>): ParameterizedType? {
            val superclass = clazz.genericSuperclass
            if (superclass is ParameterizedType) {
                return superclass
            } else if (superclass is Class<*>) {
                return findParameterizedType(superclass)
            }
            Log.e("反射", "findParameterizedType: 未找到泛型 - ${clazz.simpleName}")
            return null
        }

        /**
         * 强制显示菜单icon
         * @param menu menu
         */
        fun showMenuIcon(menu: Menu) {
            if (menu.javaClass.simpleName.equals("MenuBuilder", ignoreCase = true)) {
                try {
                    val method = menu.javaClass.getDeclaredMethod("setOptionalIconsVisible", java.lang.Boolean.TYPE)
                    method.isAccessible = true
                    method.invoke(menu, true)
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }

        /**
         * 关联一个 TabLayout 和 ViewPager2
         * @param tabLayout TabLayout
         * @param viewPager2 ViewPager2
         * @param strategy TabConfigurationStrategy
         * @return TabLayoutMediator
         */
        fun attachTabLayout(tabLayout: TabLayout, viewPager2: ViewPager2, strategy: TabLayoutMediator.TabConfigurationStrategy) =
            TabLayoutMediator(tabLayout, viewPager2, true, strategy).also { it.attach() }


    }
}